﻿using Prism.Commands;
using Prism.Regions;
using Prism.Services.Dialogs;
using SmartPlant.Services;
using SmartPlant.Services.Interfaces;
using SmartPlant.WinCore;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;
using Telerik.Windows.Data;
using Unity;

namespace SmartPlant.Core.Mvvm
{
    /// <summary>
    /// 动态GridViewModel。
    /// </summary>
    public abstract class DynamicGridViewModelBase : DynamicColumnRegionViewModel
    {
        private int _countRecord;
        private int _pageSize = 20;
        private int _pageIndex = 1;
        private bool _isBusy;
        private string _busyContent = "数据加载中.....";
        private dynamic _tableData;

        private DelegateCommand<object> _mouseDoubleClickCommand;
        private DelegateCommand<object> _pastingCommand;
        private DelegateCommand<object> _cellEditEndedCommand;
        private DelegateCommand<object> _pageIndexChangedCommand;
        private ObservableCollection<SimpleIntModel> _splitPageVirtualData;
        protected readonly IDynamicDataApi _dynamicDataApi;
        protected readonly IDialogService _dialogService;
        private readonly ICodeListService _codeListService;
        private readonly BackgroundWorker backgroundWorker;


        /// <summary>
        /// 默认构造函数。
        /// </summary>
        /// <param name="regionManager"></param>
        /// <param name="unityContainer"></param>
        /// <param name="dynamicDataApi"></param>
        /// <param name="dialogService"></param>
        public DynamicGridViewModelBase(
            IRegionManager regionManager,
            IUnityContainer unityContainer,
            IDynamicDataApi dynamicDataApi,
            IDialogService dialogService) : base(regionManager, unityContainer, dialogService)
        {
            _splitPageVirtualData = new ObservableCollection<SimpleIntModel>();
            _dynamicDataApi = dynamicDataApi;
            _dialogService = dialogService;
            _codeListService = unityContainer.Resolve<CodeListService>();
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += this.OnBackgroundWorkerDoWork;
            backgroundWorker.RunWorkerCompleted += OnBackgroundWorkerRunWorkerCompleted;
        }

        #region Prop
        /// <summary>
        /// 用于显示数据获取的进度文本。
        /// </summary>
        public string BusyContent
        {
            get { return _busyContent; }
            set { SetProperty(ref _busyContent, value); }
        }

        /// <summary>
        /// 用于表格控件显示的数据。
        /// </summary>
        public dynamic TableData
        {
            get { return _tableData; }
            set { SetProperty<dynamic>(ref _tableData, value); }
        }

        /// <summary>
        /// 当前是否处理忙碌状态。
        /// </summary>
        public virtual bool IsBusy
        {
            get { return _isBusy; }
            set
            {
                if (this._isBusy != value)
                {
                    this._isBusy = value;
                    this.OnPropertyChanged(nameof(IsBusy));
                    if (WorkerBeforeCheck())
                    {
                        if (this._isBusy && !backgroundWorker.IsBusy)
                        {
                            backgroundWorker.RunWorkerAsync();
                            return;
                        }
                    }
                    this._isBusy = false;
                    this.OnPropertyChanged(nameof(IsBusy));
                }
            }
        }

        /// <summary>
        /// 在任务开始前执行的检查，如果检查失败则不执行后台任务。
        /// </summary>
        /// <returns>返回<see cref="true"/>则检验成功，可以执行后台任务，否则不能执行。</returns>
        protected virtual bool WorkerBeforeCheck()
        {
            return true;
        }

        private void OnBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            InvokeOnUIThread(() =>
            {
                this.BackgroundWorkerLoadComplete(e);
                this.IsBusy = false;
            });
        }

        /// <summary>
        /// 后台任务数据加载完成执行的方法。
        /// </summary>
        /// <param name="e"></param>
        protected virtual void BackgroundWorkerLoadComplete(RunWorkerCompletedEventArgs e)
        {

        }

        private void OnBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            var task = ViewModelLoadAsync(null);
            while (!task.IsCompleted)
            {
                Thread.Sleep(1000);
            }
            e.Result = task.Result;
        }

        /// <summary>
        /// 用于分页的虚拟数据。
        /// </summary>
        public ObservableCollection<SimpleIntModel> SplitPageVirtualData
        {
            get { return _splitPageVirtualData; }
            set { SetProperty(ref _splitPageVirtualData, value); }
        }
        #endregion

        #region Split Page
        /// <summary>
        /// 总记录数。
        /// </summary>
        public int CountRecord
        {
            get { return _countRecord; }
            set { SetProperty(ref _countRecord, value); }
        }

        /// <summary>
        /// 分页大小。
        /// </summary>
        public int PageSize
        {
            get { return _pageSize; }
            set { SetProperty(ref _pageSize, value); }
        }

        /// <summary>
        /// 当前页。
        /// </summary>
        public int PageIndex
        {
            get { return _pageIndex; }
            set { SetProperty(ref _pageIndex, value); }
        }
        #endregion

        #region Command
        /// <summary>
        /// Grid双击命令。
        /// </summary>
        public ICommand MouseDoubleClickCommand
        {
            get
            {
                if (_mouseDoubleClickCommand != null) return _mouseDoubleClickCommand;
                _mouseDoubleClickCommand = new DelegateCommand<object>(OnMouseDoubleClickCommandAsync);
                return _mouseDoubleClickCommand;
            }
        }
        /// <summary>
        /// Grid双击命令。
        /// </summary>
        public ICommand PastingCommand
        {
            get
            {
                if (_pastingCommand != null) return _pastingCommand;
                _pastingCommand = new DelegateCommand<object>(OnPastingCommandAsync);
                return _pastingCommand;
            }
        }

        /// <summary>
        /// Grid双击命令。
        /// </summary>
        public ICommand CellEditEndedCommand
        {
            get
            {
                if (_cellEditEndedCommand != null) return _cellEditEndedCommand;
                _cellEditEndedCommand = new DelegateCommand<object>(OnCellEditEndedCommandAsync);
                return _cellEditEndedCommand;
            }
        }

        /// <summary>
        /// 分页信息更改后触发的命令。
        /// </summary>
        public ICommand PageIndexChangedCommand
        {
            get
            {
                if (_pageIndexChangedCommand != null) return _pageIndexChangedCommand;
                _pageIndexChangedCommand = new DelegateCommand<object>(OnPageIndexChangedCommandAsync);
                return _pageIndexChangedCommand;
            }
        }
        #endregion

        private void OnPageIndexChangedCommandAsync(object obj)
        {
            var args = obj as PageIndexChangedEventArgs;
            if (args != null && args.NewPageIndex != PageIndex)
            {
                this.PageIndex = args.NewPageIndex;
                this.IsBusy = true;
            }
        }

        protected override void OnInitPage(object obj)
        {
            this.IsBusy = true;
        }

        /// <summary>
        /// 鼠标双击弹出选择对话框。
        /// </summary>
        /// <param name="obj"></param>
        protected virtual void OnMouseDoubleClickCommandAsync(object obj)
        {
            var mouseButtonArgs = obj as MouseButtonEventArgs;
            var gridViewCell = (mouseButtonArgs.OriginalSource as System.Windows.UIElement).ParentOfType<GridViewCell>();

            if (gridViewCell != null && gridViewCell.Column.Tag != null)
            {
                var tag = gridViewCell.Column.Tag as SimpleModel<string, decimal>;
                var pi = _dynamicPropertyInfos.First(d => d.ItemAttributionId == tag.v2);
                string curValue = "";
                if (gridViewCell.Value != null)
                {
                    curValue = gridViewCell.Value.ToString();
                }
                _dialogService.ShowDialog("CodelistSelect",
                    new Prism.Services.Dialogs.DialogParameters($"itemId={tag.v2}&title={pi.DisplayName}&curValue={curValue}"),
                   r =>
                   {
                       if (r.Result != ButtonResult.OK)
                           return;
                       var id = r.Parameters.GetValue<string>("id");
                       var name = r.Parameters.GetValue<string>("name");
                       var pRow = gridViewCell.ParentRow.DataContext;
                       Reflect.SetPropValue(pRow, tag.v1, name);
                   });
            }
        }

        /// <summary>
        /// 批量粘贴命令处理。
        /// </summary>
        /// <param name="obj"></param>
        protected virtual async void OnPastingCommandAsync(object obj)
        {
            var args = obj as GridViewCellClipboardEventArgs;
            if (args == null)
            {
                return;
            }
            var tag = args.Cell.Column.Tag as SimpleModel<string, decimal>;
            if (tag.IsNullOrEmpty())
            {
                args.Cancel = false;
                return;
            }
            var dropDownList = await _codeListService.GetDropDownListByAttrAsync(tag.v2); //GlobalObject.GetDropDownListByAttr(tag.v2);
            if (dropDownList == null)
            {
                args.Cancel = false;
                return;
            }
            var val = args.Value.ToString();
            var dropVal = dropDownList.Find(d => d.Name == val);
            if (dropVal != null)
            {
                args.Cancel = false;
                return;
            }
            else
            {
                args.Cancel = true;
                return;
            }
        }

        /// <summary>
        /// 单元格编辑结束的处理命令，用来判断用户输入的数据是否正确。
        /// </summary>
        /// <param name="obj"></param>
        protected virtual async void OnCellEditEndedCommandAsync(object obj)
        {
            var e = obj as GridViewCellEditEndedEventArgs;
            if (e == null) return;

            var tag = e.Cell.Column.Tag as SimpleModel<string, decimal>;
            if (tag.IsNullOrEmpty())
            {
                return;
            }
            var dropDownList = await _codeListService.GetDropDownListByAttrAsync(tag.v2); //  GlobalObject.GetDropDownListByAttr(tag.v2);
            if (dropDownList == null)
            {
                return;
            }
            var val = e.NewData.ToString();
            var dropVal = dropDownList.Find(d => d.Name == val);
            if (dropVal != null)
            {
                return;
            }
            else
            {
                var pRow = e.Cell.ParentRow.DataContext;
                Reflect.SetPropValue(pRow, tag.v1, e.OldData);
                return;
            }
        }

        /// <summary>
        /// 执行后台视图数据加载服务。
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected async virtual Task<object> ViewModelLoadAsync(object model)
        {
            var i = await Task.FromResult(0);
            return null;
        }

        /// <summary>
        /// 生成分布虚拟数据。
        /// </summary>
        protected virtual List<SimpleIntModel> GenerateSplitPageVirtualData(int count)
        {
            var list = new List<SimpleIntModel>();
            for (int i = 0; i < count; i++)
            {
                list.Add(new SimpleIntModel { v1 = i });
            }
            return list;
        }

        protected static string BytesToString(long byteCount)
        {
            string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
            if (byteCount == 0)
                return "0" + suf[0];
            long bytes = Math.Abs(byteCount);
            int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
            double num = Math.Round(bytes / Math.Pow(1024, place), 1);
            return $"{(Math.Sign(byteCount) * num).ToString(CultureInfo.InvariantCulture)} {suf[place]}";
        }
    }
}
